/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.bpm.engine.impl;

import com.je.bpm.core.model.DismissNodeInfo;
import com.je.bpm.core.model.FlowNode;
import com.je.bpm.core.model.SequenceFlow;
import com.je.bpm.core.model.task.KaiteBaseUserTask;
import com.je.bpm.engine.ActivitiIllegalArgumentException;
import com.je.bpm.engine.RuntimeService;
import com.je.bpm.engine.button.validator.ButtonValidateParam;
import com.je.bpm.engine.delegate.event.ActivitiEvent;
import com.je.bpm.engine.delegate.event.ActivitiEventListener;
import com.je.bpm.engine.delegate.event.ActivitiEventType;
import com.je.bpm.engine.impl.cmd.*;
import com.je.bpm.engine.impl.persistence.entity.TaskEntityImpl;
import com.je.bpm.engine.impl.persistence.entity.VariableInstance;
import com.je.bpm.engine.impl.runtime.ProcessInstanceBuilderImpl;
import com.je.bpm.engine.runtime.*;
import com.je.bpm.engine.task.Event;
import com.je.bpm.engine.task.IdentityLink;
import com.je.bpm.engine.task.IdentityLinkType;

import java.util.*;

public class RuntimeServiceImpl extends ServiceImpl implements RuntimeService {

    @Override
    public ProcessInstance startProcessInstanceByKey(String processDefinitionKey) {
        return commandExecutor.execute(new StartProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, null, null));
    }

    @Override
    public ProcessInstance startProcessInstanceByKey(String processDefinitionKey, String businessKey) {
        return commandExecutor.execute(new StartProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, businessKey, null));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByKey(String processDefinitionKey, String assignee) {
        return commandExecutor.execute(new SponsorProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, null, assignee, null));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceById(String processDefinitionId, String assignee) {
        return commandExecutor.execute(new SponsorProcessInstanceCmd<ProcessInstance>(null, processDefinitionId, null, assignee, null));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByKey(String processDefinitionKey, String firstUser, String assignee) {
        return commandExecutor.execute(new SponsorProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, null, firstUser, assignee, null));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceById(String processDefinitionId, String firstUser, String assignee) {
        return null;
    }

    @Override
    public ProcessInstance startProcessInstanceByKeyWithBusinessKey(String processDefinitionKey, String businessKey) {
        return commandExecutor.execute(new StartProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, businessKey, null));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByKeyWithBusinessKey(String processDefinitionKey, String businessKey, String assignee) {
        return commandExecutor.execute(new SponsorProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, businessKey, assignee, null));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByKeyWithBusinessKey(String processDefinitionKey, String businessKey, String firstUser, String assignee) {
        return commandExecutor.execute(new SponsorProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, businessKey, firstUser, assignee, null));
    }

    @Override
    public ProcessInstance startProcessInstanceByKey(String processDefinitionKey, Map<String, Object> variables) {
        return commandExecutor.execute(new StartProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, null, variables));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByKey(String processDefinitionKey, String assignee, Map<String, Object> variables) {
        return commandExecutor.execute(new SponsorProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, null, assignee, variables));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByKey(String processDefinitionKey, String firstUser, String assignee, Map<String, Object> variables) {
        return commandExecutor.execute(new SponsorProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, null, firstUser, assignee, variables));
    }

    @Override
    public ProcessInstance startProcessInstanceByKeyWithBusinessKey(String processDefinitionKey, String businessKey, Map<String, Object> variables) {
        return commandExecutor.execute(new StartProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, businessKey, variables));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByKeyWithBusinessKey(String processDefinitionKey, String businessKey, String assignee, Map<String, Object> variables) {
        return commandExecutor.execute(new SponsorProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, businessKey, assignee, variables));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByKeyWithBusinessKey(String processDefinitionKey, String businessKey, String firstUser, String assignee, Map<String, Object> variables) {
        return commandExecutor.execute(new SponsorProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, businessKey, firstUser, assignee, variables));
    }

    @Override
    public ProcessInstance startProcessInstanceByKeyAndTenantId(String processDefinitionKey, String tenantId) {
        return commandExecutor.execute(new StartProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, null, null));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByKeyAndTenantId(String processDefinitionKey, String tenantId, String assignee) {
        return commandExecutor.execute(new SponsorProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, null, assignee, null, tenantId));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByKeyAndTenantId(String processDefinitionKey, String tenantId, String firstUser, String assignee) {
        return commandExecutor.execute(new SponsorProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, null, firstUser, assignee, null, tenantId));
    }

    @Override
    public ProcessInstance startProcessInstanceByKeyAndTenantId(String processDefinitionKey, String businessKey, String tenantId) {
        return commandExecutor.execute(new StartProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, businessKey, null));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByKeyAndTenantIdWithBusiness(String processDefinitionKey, String businessKey, String tenantId, String assignee) {
        return commandExecutor.execute(new SponsorProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, businessKey, assignee, null, tenantId));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByKeyAndTenantId(String processDefinitionKey, String businessKey, String tenantId, String firstUser, String assignee) {
        return commandExecutor.execute(new SponsorProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, businessKey, firstUser, assignee, null, tenantId));
    }

    @Override
    public ProcessInstance startProcessInstanceByKeyAndTenantId(String processDefinitionKey, Map<String, Object> variables, String tenantId) {
        return commandExecutor.execute(new StartProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, null, variables));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByKeyAndTenantId(String processDefinitionKey, Map<String, Object> variables, String tenantId, String assignee) {
        return commandExecutor.execute(new SponsorProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, null, assignee, variables, tenantId));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByKeyAndTenantId(String processDefinitionKey, Map<String, Object> variables, String tenantId, String firstUser, String assignee) {
        return commandExecutor.execute(new SponsorProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, null, firstUser, assignee, variables, tenantId));
    }

    @Override
    public ProcessInstance startProcessInstanceByKeyAndTenantId(String processDefinitionKey, String businessKey, Map<String, Object> variables, String tenantId) {
        return commandExecutor.execute(new StartProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, businessKey, variables));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByKeyAndTenantId(String processDefinitionKey, String businessKey, Map<String, Object> variables, String tenantId, String assignee) {
        return commandExecutor.execute(new SponsorProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, businessKey, assignee, variables, tenantId));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByKeyAndTenantId(String processDefinitionKey, String businessKey, Map<String, Object> variables, String tenantId, String firstUser, String assignee) {
        return commandExecutor.execute(new SponsorProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, businessKey, firstUser, assignee, variables, tenantId));
    }

    @Override
    public ProcessInstance startProcessInstanceById(String processDefinitionId) {
        return commandExecutor.execute(new StartProcessInstanceCmd<ProcessInstance>(null, processDefinitionId, null, null));
    }

    @Override
    public ProcessInstance startProcessInstanceByIdWithBusinessKey(String processDefinitionId, String businessKey) {
        return commandExecutor.execute(new StartProcessInstanceCmd<ProcessInstance>(null, processDefinitionId, businessKey, null));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByIdWithBusinessKey(String processDefinitionId, String businessKey, String assignee) {
        return commandExecutor.execute(new SponsorProcessInstanceCmd<ProcessInstance>(null, processDefinitionId, businessKey, assignee, null));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByIdWithBusinessKey(String processDefinitionId, String businessKey, String firstUser, String assignee) {
        return commandExecutor.execute(new SponsorProcessInstanceCmd<ProcessInstance>(null, processDefinitionId, businessKey, firstUser, assignee, null));
    }

    @Override
    public ProcessInstance startProcessInstanceById(String processDefinitionId, Map<String, Object> variables) {
        return commandExecutor.execute(new StartProcessInstanceCmd<ProcessInstance>(null, processDefinitionId, null, variables));
    }

    @Override
    public ProcessInstance startProcessInstanceByIdAndBean(String processDefinitionId, String businessKey, Map<String, Object> bean,
                                                           String prod) {
        return commandExecutor.execute(new StartProcessInstanceCmd<ProcessInstance>(
                null, processDefinitionId, businessKey, null, bean, prod));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceById(String processDefinitionId, String sequentials, String assignee, String secondTaskRef,
                                                      String prod, String businessKey, String tenantId, Map<String, Object> bean,
                                                      String comment, String isJump) {
        return commandExecutor.execute(new SponsorProcessInstanceCmd<ProcessInstance>(processDefinitionId, assignee, secondTaskRef, prod, businessKey, tenantId, bean, comment, sequentials, isJump));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceById(String processDefinitionId, String assignee, Map<String, Object> variables) {
        return commandExecutor.execute(new SponsorProcessInstanceCmd<ProcessInstance>(null, processDefinitionId, null, assignee, variables));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceById(String processDefinitionId, String firstUser, String assignee, Map<String, Object> variables) {
        return commandExecutor.execute(new SponsorProcessInstanceCmd<ProcessInstance>(null, processDefinitionId, null, firstUser, assignee, variables));
    }

    @Override
    public ProcessInstance startProcessInstanceById(String processDefinitionId, String businessKey, Map<String, Object> variables) {
        return commandExecutor.execute(new StartProcessInstanceCmd<ProcessInstance>(null, processDefinitionId, businessKey, variables));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByIdWithBusinessKey(String processDefinitionId, String businessKey, String assignee, Map<String, Object> variables) {
        return commandExecutor.execute(new SponsorProcessInstanceCmd<ProcessInstance>(null, processDefinitionId, businessKey, assignee, variables));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceById(String processDefinitionId, String businessKey, String firstUser, String assignee, Map<String, Object> variables) {
        return commandExecutor.execute(new SponsorProcessInstanceCmd<ProcessInstance>(null, processDefinitionId, businessKey, firstUser, assignee, variables));
    }

    @Override
    public void cancel(String processInstanceId, String reason, String businessKey, Map<String, Object> bean, String prod) {
        commandExecutor.execute(new CancelProcessInstanceCmd(processInstanceId, reason, businessKey, bean, prod));
    }

    @Override
    public void deleteProcessInstance(String processInstanceId, String deleteReason, String businessKey, String prod, Map<String, Object> bean) {
        commandExecutor.execute(new DeleteProcessInstanceCmd(processInstanceId, deleteReason, businessKey, prod, bean));
    }

    @Override
    public void deleteProcessInstance(String processInstanceId, String deleteReason, String prod, Map<String, Object> bean) {
        commandExecutor.execute(new DeleteProcessInstanceCmd(processInstanceId, deleteReason, prod, bean));
    }

    @Override
    public ExecutionQuery createExecutionQuery() {
        return new ExecutionQueryImpl(commandExecutor);
    }

    @Override
    public NativeExecutionQuery createNativeExecutionQuery() {
        return new NativeExecutionQueryImpl(commandExecutor);
    }

    @Override
    public NativeProcessInstanceQuery createNativeProcessInstanceQuery() {
        return new NativeProcessInstanceQueryImpl(commandExecutor);
    }

    @Override
    public void updateBusinessKey(String processInstanceId, String businessKey) {
        commandExecutor.execute(new SetProcessInstanceBusinessKeyCmd(processInstanceId, businessKey));
    }

    @Override
    public Map<String, Object> getVariables(String executionId) {
        return commandExecutor.execute(new GetExecutionVariablesCmd(executionId, null, false));
    }

    @Override
    public Map<String, VariableInstance> getVariableInstances(String executionId) {
        return commandExecutor.execute(new GetExecutionVariableInstancesCmd(executionId, null, false));
    }

    @Override
    public List<VariableInstance> getVariableInstancesByExecutionIds(Set<String> executionIds) {
        return commandExecutor.execute(new GetExecutionsVariablesCmd(executionIds));
    }

    @Override
    public Map<String, Object> getVariablesLocal(String executionId) {
        return commandExecutor.execute(new GetExecutionVariablesCmd(executionId, null, true));
    }

    @Override
    public Map<String, VariableInstance> getVariableInstancesLocal(String executionId) {
        return commandExecutor.execute(new GetExecutionVariableInstancesCmd(executionId, null, true));
    }

    @Override
    public Map<String, Object> getVariables(String executionId, Collection<String> variableNames) {
        return commandExecutor.execute(new GetExecutionVariablesCmd(executionId, variableNames, false));
    }

    @Override
    public Map<String, VariableInstance> getVariableInstances(String executionId, Collection<String> variableNames) {
        return commandExecutor.execute(new GetExecutionVariableInstancesCmd(executionId, variableNames, false));
    }

    @Override
    public Map<String, Object> getVariablesLocal(String executionId, Collection<String> variableNames) {
        return commandExecutor.execute(new GetExecutionVariablesCmd(executionId, variableNames, true));
    }

    @Override
    public Map<String, VariableInstance> getVariableInstancesLocal(String executionId, Collection<String> variableNames) {
        return commandExecutor.execute(new GetExecutionVariableInstancesCmd(executionId, variableNames, true));
    }

    @Override
    public Object getVariable(String executionId, String variableName) {
        return commandExecutor.execute(new GetExecutionVariableCmd(executionId, variableName, false));
    }

    @Override
    public VariableInstance getVariableInstance(String executionId, String variableName) {
        return commandExecutor.execute(new GetExecutionVariableInstanceCmd(executionId, variableName, false));
    }

    @Override
    public <T> T getVariable(String executionId, String variableName, Class<T> variableClass) {
        return variableClass.cast(getVariable(executionId, variableName));
    }

    @Override
    public boolean hasVariable(String executionId, String variableName) {
        return commandExecutor.execute(new HasExecutionVariableCmd(executionId, variableName, false));
    }

    @Override
    public Object getVariableLocal(String executionId, String variableName) {
        return commandExecutor.execute(new GetExecutionVariableCmd(executionId, variableName, true));
    }

    @Override
    public VariableInstance getVariableInstanceLocal(String executionId, String variableName) {
        return commandExecutor.execute(new GetExecutionVariableInstanceCmd(executionId, variableName, true));
    }

    @Override
    public <T> T getVariableLocal(String executionId, String variableName, Class<T> variableClass) {
        return variableClass.cast(getVariableLocal(executionId, variableName));
    }

    @Override
    public boolean hasVariableLocal(String executionId, String variableName) {
        return commandExecutor.execute(new HasExecutionVariableCmd(executionId, variableName, true));
    }

    @Override
    public void setVariable(String executionId, String variableName, Object value) {
        if (variableName == null) {
            throw new ActivitiIllegalArgumentException("variableName is null");
        }
        Map<String, Object> variables = new HashMap<String, Object>();
        variables.put(variableName, value);
        commandExecutor.execute(new SetExecutionVariablesCmd(executionId, variables, false));
    }

    @Override
    public void setVariableLocal(String executionId, String variableName, Object value) {
        if (variableName == null) {
            throw new ActivitiIllegalArgumentException("variableName is null");
        }
        Map<String, Object> variables = new HashMap<String, Object>();
        variables.put(variableName, value);
        commandExecutor.execute(new SetExecutionVariablesCmd(executionId, variables, true));
    }

    @Override
    public void setVariables(String executionId, Map<String, ? extends Object> variables) {
        commandExecutor.execute(new SetExecutionVariablesCmd(executionId, variables, false));
    }

    @Override
    public void setVariablesLocal(String executionId, Map<String, ? extends Object> variables) {
        commandExecutor.execute(new SetExecutionVariablesCmd(executionId, variables, true));
    }

    @Override
    public void removeVariable(String executionId, String variableName) {
        Collection<String> variableNames = new ArrayList<String>(1);
        variableNames.add(variableName);
        commandExecutor.execute(new RemoveExecutionVariablesCmd(executionId, variableNames, false));
    }

    @Override
    public void removeVariableLocal(String executionId, String variableName) {
        Collection<String> variableNames = new ArrayList<String>();
        variableNames.add(variableName);
        commandExecutor.execute(new RemoveExecutionVariablesCmd(executionId, variableNames, true));
    }

    @Override
    public void removeVariables(String executionId, Collection<String> variableNames) {
        commandExecutor.execute(new RemoveExecutionVariablesCmd(executionId, variableNames, false));
    }

    @Override
    public void removeVariablesLocal(String executionId, Collection<String> variableNames) {
        commandExecutor.execute(new RemoveExecutionVariablesCmd(executionId, variableNames, true));
    }

    @Override
    public Map<String, DataObject> getDataObjects(String executionId) {
        return commandExecutor.execute(new GetDataObjectsCmd(executionId, null, false));
    }

    @Override
    public Map<String, DataObject> getDataObjects(String executionId, String locale, boolean withLocalizationFallback) {
        return commandExecutor.execute(new GetDataObjectsCmd(executionId, null, false, locale, withLocalizationFallback));
    }

    @Override
    public Map<String, DataObject> getDataObjectsLocal(String executionId) {
        return commandExecutor.execute(new GetDataObjectsCmd(executionId, null, true));
    }

    @Override
    public Map<String, DataObject> getDataObjectsLocal(String executionId, String locale, boolean withLocalizationFallback) {
        return commandExecutor.execute(new GetDataObjectsCmd(executionId, null, true, locale, withLocalizationFallback));
    }

    @Override
    public Map<String, DataObject> getDataObjects(String executionId, Collection<String> dataObjectNames) {
        return commandExecutor.execute(new GetDataObjectsCmd(executionId, dataObjectNames, false));
    }

    @Override
    public Map<String, DataObject> getDataObjects(String executionId, Collection<String> dataObjectNames, String locale, boolean withLocalizationFallback) {
        return commandExecutor.execute(new GetDataObjectsCmd(executionId, dataObjectNames, false, locale, withLocalizationFallback));
    }

    @Override
    public Map<String, DataObject> getDataObjectsLocal(String executionId, Collection<String> dataObjects) {
        return commandExecutor.execute(new GetDataObjectsCmd(executionId, dataObjects, true));
    }

    @Override
    public Map<String, DataObject> getDataObjectsLocal(String executionId, Collection<String> dataObjectNames, String locale, boolean withLocalizationFallback) {
        return commandExecutor.execute(new GetDataObjectsCmd(executionId, dataObjectNames, true, locale, withLocalizationFallback));
    }

    @Override
    public DataObject getDataObject(String executionId, String dataObject) {
        return commandExecutor.execute(new GetDataObjectCmd(executionId, dataObject, false));
    }

    @Override
    public DataObject getDataObject(String executionId, String dataObjectName, String locale, boolean withLocalizationFallback) {
        return commandExecutor.execute(new GetDataObjectCmd(executionId, dataObjectName, false, locale, withLocalizationFallback));
    }

    @Override
    public DataObject getDataObjectLocal(String executionId, String dataObjectName) {
        return commandExecutor.execute(new GetDataObjectCmd(executionId, dataObjectName, true));
    }

    @Override
    public DataObject getDataObjectLocal(String executionId, String dataObjectName, String locale, boolean withLocalizationFallback) {
        return commandExecutor.execute(new GetDataObjectCmd(executionId, dataObjectName, true, locale, withLocalizationFallback));
    }

    public void signal(String executionId) {
        commandExecutor.execute(new TriggerCmd(executionId, null));
    }

    @Override
    public void trigger(String executionId) {
        commandExecutor.execute(new TriggerCmd(executionId, null));
    }

    public void signal(String executionId, Map<String, Object> processVariables) {
        commandExecutor.execute(new TriggerCmd(executionId, processVariables));
    }

    @Override
    public void trigger(String executionId, Map<String, Object> processVariables) {
        commandExecutor.execute(new TriggerCmd(executionId, processVariables));
    }

    @Override
    public void trigger(String executionId, Map<String, Object> processVariables, Map<String, Object> transientVariables) {
        commandExecutor.execute(new TriggerCmd(executionId, processVariables, transientVariables));
    }

    @Override
    public void addUserIdentityLink(String processInstanceId, String userId, String identityLinkType) {
        commandExecutor.execute(new AddIdentityLinkForProcessInstanceCmd(processInstanceId, userId, null, identityLinkType));
    }

    @Override
    public void addGroupIdentityLink(String processInstanceId, String groupId, String identityLinkType) {
        commandExecutor.execute(new AddIdentityLinkForProcessInstanceCmd(processInstanceId, null, groupId, identityLinkType));
    }

    @Override
    public void addParticipantUser(String processInstanceId, String userId) {
        commandExecutor.execute(new AddIdentityLinkForProcessInstanceCmd(processInstanceId, userId, null, IdentityLinkType.PARTICIPANT));
    }

    @Override
    public void addParticipantGroup(String processInstanceId, String groupId) {
        commandExecutor.execute(new AddIdentityLinkForProcessInstanceCmd(processInstanceId, null, groupId, IdentityLinkType.PARTICIPANT));
    }

    @Override
    public void deleteParticipantUser(String processInstanceId, String userId) {
        commandExecutor.execute(new DeleteIdentityLinkForProcessInstanceCmd(processInstanceId, userId, null, IdentityLinkType.PARTICIPANT));
    }

    @Override
    public void deleteParticipantGroup(String processInstanceId, String groupId) {
        commandExecutor.execute(new DeleteIdentityLinkForProcessInstanceCmd(processInstanceId, null, groupId, IdentityLinkType.PARTICIPANT));
    }

    @Override
    public void deleteUserIdentityLink(String processInstanceId, String userId, String identityLinkType) {
        commandExecutor.execute(new DeleteIdentityLinkForProcessInstanceCmd(processInstanceId, userId, null, identityLinkType));
    }

    @Override
    public void deleteGroupIdentityLink(String processInstanceId, String groupId, String identityLinkType) {
        commandExecutor.execute(new DeleteIdentityLinkForProcessInstanceCmd(processInstanceId, null, groupId, identityLinkType));
    }

    @Override
    public List<IdentityLink> getIdentityLinksForProcessInstance(String processInstanceId) {
        return commandExecutor.execute(new GetIdentityLinksForProcessInstanceCmd(processInstanceId));
    }

    @Override
    public String getStartIdentityLinksForProcessInstance(String instanceId) {
        return commandExecutor.execute(new GetStartIdentityLinksForProcessInstanceCmd(instanceId));
    }

    @Override
    public ProcessInstanceQuery createProcessInstanceQuery() {
        return new ProcessInstanceQueryImpl(commandExecutor);
    }

    @Override
    public List<String> getActiveActivityIds(String executionId) {
        return commandExecutor.execute(new FindActiveActivityIdsCmd(executionId));
    }

    @Override
    public List<Map<SequenceFlow, Boolean>> getSubmitElement(String pdid, String taskId, Map<String, Object> bean, String prod) {
        return commandExecutor.execute(new FindSubmitElementCmd(pdid, taskId, bean, prod));
    }

    @Override
    public Boolean getSubmitDirectly(String pdid, String taskId) {
        return commandExecutor.execute(new GetSubmitDirectlyCmd(pdid, taskId));
    }

    @Override
    public Object getSubmitElementAssignee(String pdid, String taskId, String target, Map<String, Object> bean, String prod) {
        return commandExecutor.execute(new FindSubmitElementAssigneeCmd(pdid, taskId, target, bean, prod));
    }

    @Override
    public Object getCurrentElementAssignee(String pdid, String taskId, String target, Map<String, Object> bean, String prod, String operationId) {
        return commandExecutor.execute(new FindCurrentElementAssigneeCmd(pdid, taskId, target, bean, prod, operationId));
    }

    @Override
    public Boolean isSubmitTheCurrentNode(String taskId, String target) {
        return commandExecutor.execute(new GetSubmitTheCurrentNodeCmd(taskId, target));
    }

    @Override
    public KaiteBaseUserTask getCurrentElement(String pdid, String executionId, String taskId, Map<String, Object> bean) {
        return commandExecutor.execute(new FindCurrentElementCmd(pdid, executionId, taskId, bean));
    }

    @Override
    public List<DismissNodeInfo> getDismissElement(String executionId, String taskId, Map<String, Object> bean) {
        return commandExecutor.execute(new FindDismissElementCmd(executionId, taskId, bean));
    }

    @Override
    public void suspendProcessInstanceById(String processInstanceId) {
        commandExecutor.execute(new SuspendProcessInstanceCmd(processInstanceId));
    }

    @Override
    public void activateProcessInstanceById(String processInstanceId) {
        commandExecutor.execute(new ActivateProcessInstanceCmd(processInstanceId));
    }

    @Override
    public ProcessInstance startProcessInstanceByMessage(String messageName) {
        return commandExecutor.execute(new StartProcessInstanceByMessageCmd(messageName, null, null, null));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByMessage(String messageName, String assignee) {
        return commandExecutor.execute(new SponsorProcessInstanceByMessageCmd(messageName, null, assignee, null, null));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByMessage(String messageName, String firstUser, String assignee) {
        return commandExecutor.execute(new SponsorProcessInstanceByMessageCmd(messageName, null, firstUser, assignee, null, null));
    }

    @Override
    public ProcessInstance startProcessInstanceByMessageAndTenantId(String messageName, String tenantId) {
        return commandExecutor.execute(new StartProcessInstanceByMessageCmd(messageName, null, null, tenantId));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByMessageAndTenantId(String messageName, String tenantId, String assignee) {
        return commandExecutor.execute(new SponsorProcessInstanceByMessageCmd(messageName, null, assignee, null, tenantId));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByMessageAndTenantId(String messageName, String tenantId, String firstUser, String assignee) {
        return commandExecutor.execute(new SponsorProcessInstanceByMessageCmd(messageName, null, firstUser, assignee, null, tenantId));
    }

    @Override
    public ProcessInstance startProcessInstanceByMessageWithBusinessKey(String messageName, String businessKey) {
        return commandExecutor.execute(new StartProcessInstanceByMessageCmd(messageName, businessKey, null, null));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByMessageWithBusinessKey(String messageName, String businessKey, String assignee) {
        return commandExecutor.execute(new SponsorProcessInstanceByMessageCmd(messageName, businessKey, assignee, null, null));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByMessageWithBusinessKey(String messageName, String businessKey, String firstUser, String assignee) {
        return commandExecutor.execute(new SponsorProcessInstanceByMessageCmd(messageName, businessKey, firstUser, assignee, null, null));
    }

    @Override
    public ProcessInstance startProcessInstanceByMessageAndTenantIdWithBusinessKey(String messageName, String businessKey, String tenantId) {
        return commandExecutor.execute(new StartProcessInstanceByMessageCmd(messageName, businessKey, null, tenantId));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByMessageAndTenantIdWithBusinessKey(String messageName, String businessKey, String tenantId, String assignee) {
        return commandExecutor.execute(new SponsorProcessInstanceByMessageCmd(messageName, businessKey, assignee, null, tenantId));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByMessageAndTenantIdWithBusinessKey(String messageName, String businessKey, String tenantId, String firstUser, String assignee) {
        return commandExecutor.execute(new SponsorProcessInstanceByMessageCmd(messageName, businessKey, firstUser, assignee, null, tenantId));
    }

    @Override
    public ProcessInstance startProcessInstanceByMessage(String messageName, Map<String, Object> processVariables) {
        return commandExecutor.execute(new StartProcessInstanceByMessageCmd(messageName, null, processVariables, null));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByMessage(String messageName, String assignee, Map<String, Object> processVariables) {
        return commandExecutor.execute(new SponsorProcessInstanceByMessageCmd(messageName, null, assignee, processVariables, null));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByMessage(String messageName, String firstUser, String assignee, Map<String, Object> processVariables) {
        return commandExecutor.execute(new SponsorProcessInstanceByMessageCmd(messageName, null, firstUser, assignee, processVariables, null));
    }

    @Override
    public ProcessInstance startProcessInstanceByMessageAndTenantId(String messageName, Map<String, Object> processVariables, String tenantId) {
        return commandExecutor.execute(new StartProcessInstanceByMessageCmd(messageName, null, processVariables, tenantId));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByMessageAndTenantId(String messageName, Map<String, Object> processVariables, String tenantId, String assignee) {
        return commandExecutor.execute(new SponsorProcessInstanceByMessageCmd(messageName, null, assignee, processVariables, tenantId));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByMessageAndTenantId(String messageName, Map<String, Object> processVariables, String tenantId, String firstUser, String assignee) {
        return commandExecutor.execute(new SponsorProcessInstanceByMessageCmd(messageName, null, firstUser, assignee, processVariables, tenantId));
    }

    @Override
    public ProcessInstance startProcessInstanceByMessage(String messageName, String businessKey, Map<String, Object> processVariables) {
        return commandExecutor.execute(new StartProcessInstanceByMessageCmd(messageName, businessKey, processVariables, null));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByMessage(String messageName, String businessKey, Map<String, Object> processVariables, String assignee) {
        return commandExecutor.execute(new SponsorProcessInstanceByMessageCmd(messageName, businessKey, assignee, processVariables, null));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByMessage(String messageName, String businessKey, Map<String, Object> processVariables, String firstUser, String assignee) {
        return commandExecutor.execute(new SponsorProcessInstanceByMessageCmd(messageName, businessKey, firstUser, assignee, processVariables, null));
    }

    @Override
    public ProcessInstance startProcessInstanceByMessageAndTenantId(String messageName, String businessKey, Map<String, Object> processVariables, String tenantId) {
        return commandExecutor.execute(new StartProcessInstanceByMessageCmd(messageName, businessKey, processVariables, tenantId));
    }

    @Override
    public ProcessInstance sponsorProcessInstanceByMessageAndTenantId(String messageName, String businessKey, Map<String, Object> processVariables, String tenantId, String firstUser, String assignee) {
        return commandExecutor.execute(new SponsorProcessInstanceByMessageCmd(messageName, businessKey, firstUser, assignee, processVariables, tenantId));
    }

    @Override
    public void signalEventReceived(String signalName) {
        commandExecutor.execute(new SignalEventReceivedCmd(signalName, null, null, null));
    }

    @Override
    public void signalEventReceivedWithTenantId(String signalName, String tenantId) {
        commandExecutor.execute(new SignalEventReceivedCmd(signalName, null, null, tenantId));
    }

    @Override
    public void signalEventReceivedAsync(String signalName) {
        commandExecutor.execute(new SignalEventReceivedCmd(signalName, null, true, null));
    }

    @Override
    public void signalEventReceivedAsyncWithTenantId(String signalName, String tenantId) {
        commandExecutor.execute(new SignalEventReceivedCmd(signalName, null, true, tenantId));
    }

    @Override
    public void signalEventReceived(String signalName, Map<String, Object> processVariables) {
        commandExecutor.execute(new SignalEventReceivedCmd(signalName, null, processVariables, null));
    }

    @Override
    public void signalEventReceivedWithTenantId(String signalName, Map<String, Object> processVariables, String tenantId) {
        commandExecutor.execute(new SignalEventReceivedCmd(signalName, null, processVariables, tenantId));
    }

    @Override
    public void signalEventReceived(String signalName, String executionId) {
        commandExecutor.execute(new SignalEventReceivedCmd(signalName, executionId, null, null));
    }

    @Override
    public void signalEventReceived(String signalName, String executionId, Map<String, Object> processVariables) {
        commandExecutor.execute(new SignalEventReceivedCmd(signalName, executionId, processVariables, null));
    }

    @Override
    public void signalEventReceivedAsync(String signalName, String executionId) {
        commandExecutor.execute(new SignalEventReceivedCmd(signalName, executionId, true, null));
    }

    @Override
    public void messageEventReceived(String messageName, String executionId) {
        commandExecutor.execute(new MessageEventReceivedCmd(messageName, executionId, null));
    }

    @Override
    public void messageEventReceived(String messageName, String executionId, Map<String, Object> processVariables) {
        commandExecutor.execute(new MessageEventReceivedCmd(messageName, executionId, processVariables));
    }

    @Override
    public void messageEventReceivedAsync(String messageName, String executionId) {
        commandExecutor.execute(new MessageEventReceivedCmd(messageName, executionId, true));
    }

    @Override
    public void addEventListener(ActivitiEventListener listenerToAdd) {
        commandExecutor.execute(new AddEventListenerCommand(listenerToAdd));
    }

    @Override
    public void addEventListener(ActivitiEventListener listenerToAdd, ActivitiEventType... types) {
        commandExecutor.execute(new AddEventListenerCommand(listenerToAdd, types));
    }

    @Override
    public void removeEventListener(ActivitiEventListener listenerToRemove) {
        commandExecutor.execute(new RemoveEventListenerCommand(listenerToRemove));
    }

    @Override
    public void dispatchEvent(ActivitiEvent event) {
        commandExecutor.execute(new DispatchEventCommand(event));
    }

    @Override
    public void setProcessInstanceName(String processInstanceId, String name) {
        commandExecutor.execute(new SetProcessInstanceNameCmd(processInstanceId, name));
    }

    @Override
    public List<Event> getProcessInstanceEvents(String processInstanceId) {
        return commandExecutor.execute(new GetProcessInstanceEventsCmd(processInstanceId));
    }

    @Override
    public ButtonValidateParam getTaskButtonVariable(ButtonValidateParam buttonValidateParam) {
        return commandExecutor.execute(new GetTaskButtonVariableCmd(buttonValidateParam));
    }

    @Override
    public Map<String, Object> getTaskEntityVariables(String taskId) {
        return commandExecutor.execute(new GetTaskEntityCmd(taskId));
    }

    @Override
    public Map<String, Object> getMultiInstanceTaskRootExecutionVariables(TaskEntityImpl taskEntity) {
        return commandExecutor.execute(new GetMultiInstanceTaskRootExecutionVariablesCmd(taskEntity));
    }

    @Override
    public List<FlowNode> getEnabledActivitiesFromAdhocSubProcess(String executionId) {
        return commandExecutor.execute(new GetEnabledActivitiesForAdhocSubProcessCmd(executionId));
    }

    @Override
    public Execution executeActivityInAdhocSubProcess(String executionId, String activityId) {
        return commandExecutor.execute(new ExecuteActivityForAdhocSubProcessCmd(executionId, activityId));
    }

    @Override
    public void completeAdhocSubProcess(String executionId) {
        commandExecutor.execute(new CompleteAdhocSubProcessCmd(executionId));
    }

    @Override
    public ProcessInstanceBuilder createProcessInstanceBuilder() {
        return new ProcessInstanceBuilderImpl(this);
    }

    @Override
    public ProcessInstance startCreatedProcessInstance(ProcessInstance createdProcessInstance, Map<String, Object> variables) {
        return commandExecutor.execute(new StartCreatedProcessInstanceCmd<>(createdProcessInstance, variables));
    }

    public ProcessInstance startProcessInstance(ProcessInstanceBuilderImpl processInstanceBuilder) {
        if (processInstanceBuilder.hasProcessDefinitionIdOrKey()) {
            return commandExecutor.execute(new StartProcessInstanceCmd<ProcessInstance>(processInstanceBuilder));
        } else if (processInstanceBuilder.getMessageName() != null) {
            return commandExecutor.execute(new StartProcessInstanceByMessageCmd(processInstanceBuilder));
        } else {
            throw new ActivitiIllegalArgumentException("No processDefinitionId, processDefinitionKey nor messageName provided");
        }
    }

    public ProcessInstance createProcessInstance(ProcessInstanceBuilderImpl processInstanceBuilder) {
        if (processInstanceBuilder.hasProcessDefinitionIdOrKey()) {
            return commandExecutor.execute(new CreateProcessInstanceCmd(processInstanceBuilder));
        } else {
            throw new ActivitiIllegalArgumentException("No processDefinitionId, processDefinitionKey nor messageName provided");
        }
    }


    @Override
    public String getCurrentTarget(String taskId) {
        return commandExecutor.execute(new GetCurrentTargetCmd(taskId));
    }


    @Override
    public List<String> getAssigneeByTaskIdAndCurrentNodeId(String taskId, String currentNodeId) {
        return commandExecutor.execute(new GetAssigneeByTaskIdAndCurrentNodeIdCmd(taskId,currentNodeId));
    }
}
